/*
 * main.c
 *
 *  Created on: 10/10/2011
 *      Author: utn_so
 */

#include "libPRAID.h"

t_log* loguear;
tConfig config;
tCola *colaGral;
tLista *listaDiscos;
int32_t cantDiscos;
pthread_mutex_t bloqueaColaGral;
pthread_mutex_t bloqueaListaDiscos;
sem_t semaforoLista;
tDiscoCHS chs;
int32_t sincro;

int32_t main ()
{
	/* CONEXIONES: Escuchar conexiones con PPD Cuando uno o mas se conectan puede conectarse PFS con PRAID
	 * de lo contrario PRAID debera rechazarlo e informar que aun no esta activo
	 * Una vez conectado con PPD: atender pedidos, cuando el disco responde: enviar al PFS */

	/* 		Creo el Log 			*/
	extern t_log *loguear;
	loguear = log_create("PRAID", "log.txt", INFO | ERROR, M_CONSOLE_ENABLE);


	/*            Leer Cfg            */

	config = abrirArchivoConfig ();

	/*               Crear lista de peticiones general, lista de discos e inicializar semaforos        */

	crearListaDiscos();
	crearColaGral ();
	inicializarSemaforosYMutex ();

	/*           Creo el hilo DistribuirPedidos            */

	pthread_t hiloSincro;
	pthread_create (&hiloSincro, NULL, (void *) &distribuirPedidos, (tLista *) &listaDiscos);

	/* 			Conexion 			*/

	int32_t cantSockets = 2;
	struct pollfd *pollfds;
	pollfds = (struct pollfd *)calloc(cantSockets,sizeof(struct pollfd));
	int32_t socketFS, socketPD;

	socketPD = AFINET_abrir_conexion(config.puertoPD);
	socketFS = AFINET_abrir_conexion(config.puertoFS);

	setearFD(pollfds, socketPD);
	setearFD(pollfds, socketFS);

	int32_t cantRespuestas = 0;
	int32_t cantAceptados = 0;
	int32_t timeout_msecs = -1;
	pthread_t hiloDisco;
	int32_t nvoSocketPD, nvoSocketFS;
	int32_t valorDeRetorno = 0;
	t_NIPC nipcRecibido;
	tNodoLista *ptrDisco = NULL;
	int32_t idDisco=0;
	int32_t retorno;
	int32_t valor=0;

	int32_t i,j;

	while (1)
	{
		cantRespuestas = poll(pollfds, cantAceptados + cantSockets, timeout_msecs);
		i = 0;
		j = 0;

		while (i < cantSockets + cantAceptados && j < cantRespuestas)
		{
			if ((pollfds[i].revents & POLLIN) && pollfds[i].fd == socketPD)
			{
				nvoSocketPD = aceptar_conexion(pollfds[i].fd);
				if (nvoSocketPD > 0)
				{
					retorno = handshakePPD (nvoSocketPD, &idDisco);
					if (retorno == 1)
					{
						ptrDisco = agregarDisco (nvoSocketPD, &idDisco);
						discosConectados (); // mantengo actualizada cantDiscos
						if (cantDiscos == 1)
						{
							sincro = chs.c*chs.h*chs.s;
							ptrDisco->sincro = sincro;
							if (config.flagConsola == 1)
								log_info(loguear, "PRAID", "El proceso RAID entró en funcionamiento");
						}
						pthread_create (&hiloDisco, NULL, (void *) &iniciarComunicacionPD, (void *) ptrDisco);
					}
					//else if (config.flagConsola == 1)
						//log_error (loguear, "PRAID", "Message Error: %s", "Error al realizar el Handshake con el PPD");
				}
				//else if (nvoSocketPD < 0 && config.flagConsola == 1) //
					//log_error (loguear, "PRAID", "Message Error: %s", "No se pudo conectar al PPD"); //
			}
			else if ((pollfds[i].revents & POLLIN) &&  pollfds[i].fd == socketFS)
			{
				nvoSocketFS = aceptar_conexion(socketFS);
				if (cantAceptados == 0)
					valor = handshakePFS (nvoSocketFS, &idDisco);
				if (valor != -1)
				{
					cantAceptados++;
					pollfds = realloc(pollfds,(cantAceptados + cantSockets) * sizeof(struct pollfd));
					memset(&pollfds[cantAceptados + cantSockets - 1],'\0',sizeof(struct pollfd));
					setearFD (pollfds, nvoSocketFS);

				}
				j++;
			}
			else if (pollfds[i].revents & POLLIN)
			{
				valorDeRetorno =  NIPC_recibir (pollfds[i].fd, &nipcRecibido);
				recibirPedidosFS (pollfds[i].fd, nipcRecibido);
				NIPC_destruirpaquete(&nipcRecibido);
				j++;
			}
			i++;
		}
	}

	/*		Destruyo el log		*/
	log_destroy(loguear);

	return 0;
}
